#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include "../include/common_buf.h"
#include "../include/buf_pool.h"
#include "../include/tcp_server.h"
#include "../include/Epoll.h"
#include <ext/hash_map>
#include <unordered_map>

// 临时的收发消息
struct message
{
    char data[m4K];
    char len;
};
struct message msg;

void server_rd_callback(event_loop *loop, int fd, void *args);
void server_wt_callback(event_loop *loop, int fd, void *args);

//...省略其他代码
//...省略其他代码

// server read_callback
void server_rd_callback(event_loop *loop, int fd, void *args)
{
    int ret = 0;

    struct message *msg = (struct message *)args;
    input_buf ibuf;

    ret = ibuf.read_data(fd);
    if (ret == -1)
    {
        fprintf(stderr, "ibuf read_data error\n");
        // 删除事件
        loop->del_io_event(fd);
        // 对端关闭
        close(fd);
        return;
    }
    if (ret == 0)
    {
        // 删除事件
        loop->del_io_event(fd);
        // 对端关闭
        close(fd);
        return;
    }

    printf("ibuf.length() = %d\n", ibuf.length());

    // 将读到的数据放在msg中
    msg->len = ibuf.length();
    bzero(msg->data, msg->len);
    memcpy(msg->data, ibuf.data(), msg->len);

    ibuf.pop(msg->len);
    ibuf.adjust();

    printf("recv data = %s\n", msg->data);

    // 删除读事件，添加写事件
    loop->del_io_event(fd, EPOLLIN);
    loop->add_io_event(fd, server_wt_callback, EPOLLOUT, msg);
}

// server write_callback
void server_wt_callback(event_loop *loop, int fd, void *args)
{
    struct message *msg = (struct message *)args;
    output_buf obuf;

    // 回显数据
    obuf.send_data(msg->data, msg->len);
    while (obuf.length())
    {
        int write_ret = obuf.write_data(fd);
        if (write_ret == -1)
        {
            fprintf(stderr, "write connfd error\n");
            return;
        }
        else if (write_ret == 0)
        {
            // 不是错误，表示此时不可写
            break;
        }
    }

    // 删除写事件，添加读事件
    loop->del_io_event(fd, EPOLLOUT);
    loop->add_io_event(fd, server_rd_callback, EPOLLIN, msg);
}

void tcp_server::do_accept()
{
    int clientfd = -1;
    fprintf(stderr,"begin to accept\n");
    while (true)
    {
        clientfd = accept(_sockfd, (struct sockaddr *)&_connaddr, &_addrlen);
        if (clientfd == -1)
        {
            // 如果发生了中断
            if (errno == EINTR)
            {
                fprintf(stderr, "accept errno=EINTR\n");
                continue;
            }
            // 如果链接太多
            else if (errno == EMFILE)
            {
                fprintf(stderr, "accept errno=EMFILE\n");
                break;
            }
            // 在非阻塞模式下调用了阻塞操作，在该操作没有完成就返回这个错误
            else if (errno == EAGAIN)
            {
                fprintf(stderr, "accept errno=EAGAIN\n");
                exit(1);
            }
            else
            {
                fprintf(stderr, "accept failed\n");
                exit(1);
            }
        }
        else
        {
            // 添加一些保活机制
            // 向服务器发送消息
            this->_loop->add_io_event(clientfd, server_rd_callback, EPOLLIN, &msg);
            fprintf(stderr, "accept ip:%s,port:%d\n", inet_ntoa(_connaddr.sin_addr), _connaddr.sin_port);
            break;
        }
    }
}

// listen fd 客户端有新链接请求过来的回调函数
void accept_callback(event_loop *loop, int fd, void *args)
{
    tcp_server *server = (tcp_server *)args;
    server->do_accept();
}

void lars_hello()
{
    std::cout << "lars hello" << std::endl;
}

tcp_server::tcp_server(event_loop *loop, const char *ip, uint16_t port)
{
    bzero(&_connaddr, sizeof(_connaddr));
    // 忽略掉一些信号
    // SIGPIPE:如果客户端关闭，服务端再次write就会产生
    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
    {
        fprintf(stderr, "signal ignore sigpipe\n");
    }
    // SIGHUP:如果terminal关闭，会给当前进程发送该信号
    if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
    {
        fprintf(stderr, "signal ignore sighup\n");
    }
    // 创建listen套接字
    _sockfd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
    if (_sockfd == -1)
    {
        fprintf(stderr, "tcp_server:socket create err!\n");
        exit(-1);
    }

    // 初始化地址
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(_connaddr));
    server_addr.sin_family = AF_INET;
    inet_aton(ip, &server_addr.sin_addr);
    server_addr.sin_port = htons(port);
    int op = 1;
    // 设置为不等待，套接字可立即被使用
    if (setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op)) < 0)
    {
        fprintf(stderr, "tcp_server::setsockopt err!\n");
    }
    if (bind(_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        fprintf(stderr, "tpc_server::setsockopt err!\n");
    }
    if (listen(_sockfd, 128) == -1)
    {
        fprintf(stderr, "tcp_server::listen err\n");
    }
    _loop = loop;
    _loop->add_io_event(_sockfd, accept_callback, EPOLLIN, this);
}

tcp_server::~tcp_server()
{
    close(_sockfd);
}